// 
// Facade.ts
// Author:qiuchun(362460803@qq.com)
// Time:2023.05.09 15:50:01
// Desc:装饰类
//

import Mediator from "./Mediator";
import Proxy from "./Proxy";
import Notification from "./Notification";
import ObserverMap from "./ObserverMap";
import View from "./View";
import { Presenter } from "./Presenter";
import Controller from "./Controller";
import Model from "./Model";
import Notifier from "./Notifier";
import { error, warn } from "cc";

//规范调用需要的功能
export default class Facade {
    static instance: Facade;
    static getInstance(): Facade {
        if (this.instance == null) {
            this.instance = new Facade();
        }

        return this.instance;
    };

    private model: Model = null;
    private controller: Controller = null;
    private view: View = null;

    constructor() {
        this.initializeFacade();
    }

    initializeFacade = function () {
        this.initializeModel();
        this.initializeController();
        this.initializeView();
    };
    initializeModel = function () {
        if (!this.model) {
            this.model = Model.getInstance();
        }
    };
    initializeController = function () {
        if (!this.controller) {
            this.controller = Controller.getInstance();
        }
    };
    initializeView = function () {
        if (!this.view) {
            this.view = View.getInstance();
        }
    };

    //Presenter封装
    registerPresenter(presenterName: string, presenter: Presenter): void {
        if (presenterName.indexOf("Presenter") < 0) {
            console.warn("mvp warn: presenterName = " + presenterName + " is not standard.")
        }
        presenter.setName(presenterName);
        Controller.getInstance().registerItem(presenter);
    };
    retrievePresenter(presenterName: string): Presenter {

        let item = Controller.getInstance().retrieveItem(presenterName) as Presenter;

        if (!item) {
            console.log("mvp error:name = " + presenterName + ",presenter is null!");
            return undefined;
        }

        //由于三个模型都是继承于Notifier，为了防止插入错误，所以需要添加判断
        if ((item instanceof Presenter) == false) {
            console.log("mvp error:name = " + presenterName + ",item is not a presenter type!");
            return undefined;
        }
        return item;
    }
    removePresenter(presenterName: string): Presenter {
        return Controller.getInstance().removeItem(presenterName) as Presenter;
    };
    hasPresenter(presenterName: string): boolean {
        return Controller.getInstance().hasItem(presenterName);
    };

    //Proxy封装
    registerProxy(proxyName: string, proxy: Proxy): void {
        if (proxyName == null) {
            error("proxyName is null");
            return;
        }
        if (proxy == null) {
            error("name = " + proxyName + ",proxy is null");
            return;
        }
        if (proxyName.indexOf("Proxy") < 0) {
            warn("mvp warn: proxyName = \'" + proxyName + "\' is not standard.")
        }
        proxy.setName(proxyName);
        Model.getInstance().registerItem(proxy);
    };
    retrieveProxy(proxyName: string): Proxy {
        let item = Model.getInstance().retrieveItem(proxyName) as Proxy;

        if (!item) {
            error("mvp error:name = " + proxyName + ",proxy is null!");
            return undefined;
        }

        //由于三个模型都是继承于Notifier，为了防止插入错误，所以需要添加判断
        if ((item instanceof Proxy) == false) {
            error("mvp error:name = \'" + proxyName + "\',item is not a Proxy type!");
            return undefined;
        }

        return item;
    };
    removeProxy(proxyName: string): Proxy {
        return Model.getInstance().removeItem(proxyName) as Proxy;
    };
    hasProxy(proxyName: string): boolean {
        return Model.getInstance().hasItem(proxyName);
    };

    //Mediator封装
    registerMediator(mediator: Mediator): void {
        if (mediator == null) {
            error("mediator is null");
            return;
        }
        if (mediator.getName().indexOf("View") < 0) {
            warn("mvp warn: Mediator Name = \'" + mediator.getName() + "\' is not standard.")
        }
        View.getInstance().registerItem(mediator);
    }
    //不提倡使用
    retrieveMediator(mediatorName: string): Mediator {
        // return View.getInstance().retrieveItem(mediatorName) as Mediator;
        warn("presenter和mediator应通过消息沟通，presenter不应该直接调用Mediator。")
        return null;
    }
    removeMediator(mediatorName: string): Mediator {
        return View.getInstance().removeItem(mediatorName) as Mediator;
    };
    hasMediator(mediatorName: string): boolean {
        return View.getInstance().hasItem(mediatorName);
    }

    //发送消息封装
    //已封装到presenter和mediator里，不提倡单独调用。
    //广播消息
    notifyObservers(notification: Notification, dest?: Notifier | string): void {
        //装饰类虽然被设计成单利模式，但是发送消息只限于Presenter和Mediator之间，这样才能保持mvp的框架。
        //如果这个函数可以在Proxy被调用，那实际上就变成mvc
        //这个框架实际是mvp和mvc都可以，关键看如何规范使用，代码设计没办法去考虑程序员规范上的事情。
        //在实际操作中，哪怕是mvc模式，但是实践起来，没有规范引导也会变成mv模式。业务逻辑直接放到view里面，然后直接调用model提取数据。
        ObserverMap.getInstance().notifyObservers(notification);
    }

    sendNotification(name: string, body?: object, type?: string, dest?: Notifier | string) {
        if (typeof body === "undefined") { body = null; }
        if (typeof type === "undefined") { type = null; }
        this.notifyObservers(new Notification(name, body, type), dest);
    };
}